﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Xml;
using System.Collections;
using RAP.Framework.Libary.Utils;
using RAP.Framework.Libary.ServerCacheManager.CacheProxy;
using System.Threading.Tasks;
using RAP.Framework.Libary.Configuration;

namespace RAP.Framework.Libary.ServerCacheManager
{
  /// <summary>
  /// 服务端缓存管理对象
  /// </summary>
  public class CacheManager : ICacheManager
  {
    #region consts
    /// <summary>
    /// caches
    /// </summary>
    public const string CONFIG_ROOT_FIELD = "caches";

    /// <summary>
    /// types
    /// </summary>
    public const string CONFIG_TYPES_FIELD = "types";

    /// <summary>
    /// proxies
    /// </summary>
    public const string CONFIG_PROXIES_FIELD = "proxies";

    /// <summary>
    /// type
    /// </summary>
    public const string CONFIG_CACHE_TYPE_FIELD = "type";

    #endregion consts

    #region static
    private static object lockObject = new object();
    private static ICacheManager _instance = null;
    public static string CONFIG_SECTION_NAME = "ServerCacheManager";
    public static string DEFAULT_CACHE_PROXY_KEY = "DefaultCacheProxy";

    /// <summary>
    /// 
    /// </summary>
    public static event Action<IDictionary> OnErrorEvent;

    /// <summary>
    /// 获取单态的缓存代理管理器
    /// </summary>
    public static ICacheManager Instance
    {
      get
      {
        return _instance;
      }
    }

    /// <summary>
    /// 构造缓存键
    /// </summary>
    /// <param name="proxyKey">缓存代理的Id</param>
    /// <param name="objectKey">主缓存对象的Id</param>
    /// <param name="valueKeys">值的Id</param>
    /// <returns></returns>
    public static string GenerateCacheKey(string proxyKey, string objectKey = null, params string[] valueKeys)
    {
      if (proxyKey.IsNullOrEmpty())
      {
        return null;
      }
      IList<string> listKeys = new List<string>();
      listKeys.Add(proxyKey);
      if (objectKey.IsNotNullOrEmpty())
      {
        listKeys.Add(objectKey);
      }
      listKeys.Add(valueKeys);
      return listKeys.Join(".");
    }
    #endregion

    public CacheManager(IConfigurationManager configurationManager)
    {
      if (_instance != null)
      {
        throw new Exception("CacheManager实例已存在！");
      }
      var cacheConfigs = configurationManager.ToDictionary(CONFIG_ROOT_FIELD);
      if (cacheConfigs.IsNotNullOrEmpty())
      {
        //从配置对象实例化缓存配置
        var types = cacheConfigs.ToDictionary(CONFIG_TYPES_FIELD);
        var proxies = cacheConfigs.ToDictionary(CONFIG_PROXIES_FIELD);

        types.Each(item =>
       {
         this.RegisterCacheType(item.Key.ToString(), item.Value.ToString());
       });

        proxies.Each(item =>
       {
         var config = item.Value as IDictionary;
         var type = config.ToString(CONFIG_CACHE_TYPE_FIELD);
         if (type.IsNotNullOrEmpty())
         {
           this.RegisterCacheProxy(item.Key.ToString(), type, config);
         }
       });
      }
      _instance = this;
    }

    protected IDictionary _htCacheProxy = new Hashtable();
    protected IDictionary<string, string> _cacheTypesCache = new Dictionary<string, string>();

    /// <summary>
    /// 获取指定Key的缓存代理对象
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public ICacheProxy this[string key]
    {
      get
      {
        return _htCacheProxy[key] as ICacheProxy;
      }
    }

    /// <summary>
    /// 获取指定完全键的值
    /// </summary>
    /// <param name="fullKey">完全键</param>
    /// <returns></returns>
    public object Get(string fullKey)
    {
      if (fullKey.IsNullOrEmpty())
      {
        return null;
      }
      CacheKey keyObj = CacheKey.Create(fullKey);
      if (keyObj == null)
      {
        return null;
      }
      return this.Get(keyObj);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fullKey"></param>
    /// <param name="funDefaultValue"></param>
    /// <returns></returns>
    public object Get(string fullKey, Func<object> funDefaultValue)
    {
      return this.Get(fullKey).IsNullValue<object>(funDefaultValue);
    }

    public object Get(CacheKey keyObj)
    {
      if (keyObj == null)
      {
        return null;
      }
      ICacheProxy proxy = this[keyObj.ProxyKey];
      if (proxy == null)
      {
        return null;
      }
      if (keyObj.ObjectKey.IsNullOrEmpty())
      {
        return proxy.ServerCache;
      }
      IDictionary cacheObject = proxy.GetCacheObject(keyObj);
      if (keyObj.ValueKey.IsNullOrEmpty())
      {
        return cacheObject != null ? cacheObject : proxy.ServerCache[keyObj.ObjectKey];
      }
      return cacheObject.GetValue(keyObj.ValueKey);
    }

    /// <summary>
    /// 获取指定完全键的值
    /// </summary>
    /// <typeparam name="T">指定类型</typeparam>
    /// <param name="fullKey">完全键</param>
    /// <returns></returns>
    public T Get<T>(string fullKey, T defaultValue = default(T))
    {
      object value = this.Get(fullKey);
      if (value == null)
      {
        return defaultValue;
      }
      if (value is IConvertible)
      {
        return (T)Convert.ChangeType(value, typeof(T));
      }
      else
      {
        return (T)value;
      }

    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fullKey"></param>
    /// <param name="funDefaultValue"></param>
    /// <returns></returns>
    public T Get<T>(string fullKey, Func<T> funDefaultValue)
    {
      object value = this.Get(fullKey);
      if (value == null)
      {
        return funDefaultValue();
      }
      return (T)Convert.ChangeType(value, typeof(T));
    }

    /// <summary>
    /// 检测是否包含指定键值
    /// </summary>
    /// <param name="fullKey"></param>
    /// <returns></returns>
    public bool Contains(string fullKey)
    {
      return this.Get(fullKey) != null;
    }

    /// <summary>
    /// 检测是否包含指定键值
    /// </summary>
    /// <param name="fullKey"></param>
    /// <returns></returns>
    public async Task<bool> ContainsAsync(string fullKey)
    {
      return await Task.Run<bool>(() =>
     {
       return this.Contains(fullKey);
     });
    }

    /// <summary>
    /// 获取指定完全键的值
    /// </summary>
    /// <param name="fullKey">完全键</param>
    /// <param name="valueOutter">指定获取到的值存储的容器</param>
    /// <returns></returns>
    public ICacheManager Get(string fullKey, IDictionary valueOutter)
    {
      if (valueOutter.IsNullOrEmpty())
      {
        throw new NullReferenceException("valueOutter不能为空！");
      }
      CacheKey keyObj = CacheKey.Create(fullKey);
      if (keyObj.IsNullOrEmpty())
      {
        return this;
      }
      valueOutter[keyObj.ValueKey] = this.Get(keyObj);
      return this;
    }

    /// <summary>
    /// 异步等待方式获取缓存
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fullKey"></param>
    /// <returns></returns>
    public async Task<T> GetAsync<T>(string fullKey)
    {
      return await Task.Run<T>(() =>
     {
       return this.Get<T>(fullKey);
     });
    }

    /// <summary>
    /// 设置指定完全键的值
    /// </summary>
    /// <param name="fullKey">完全键</param>
    /// <param name="value">要设置的值</param>
    /// <returns>返回缓存键值对象</returns>
    public ICacheManager Set(string fullKey, object value)
    {
      if (fullKey.IsNullOrEmpty())
      {
        throw new Exception("错误的键！" + fullKey);
      }
      CacheKey keyObj = CacheKey.Create(fullKey);
      if (keyObj.IsNullOrEmpty())
      {
        return null;
      }
      ICacheProxy proxy = this[keyObj.ProxyKey];
      if (proxy.IsNullOrEmpty())
      {
        return null;
      }
      if (keyObj.ValueKey.IsNullOrEmpty())
      {
        proxy.ServerCache[keyObj.ObjectKey] = value;
        return this;
      }
      IDictionary cacheObject = proxy.GetCacheObject(keyObj);
      cacheObject[keyObj.ValueKey] = value;
      return this;
    }

    /// <summary>
    /// 异步提交缓存，不等待
    /// </summary>
    /// <param name="fullKey"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public void SetAsync(string fullKey, object value)
    {
      Task.Run(() =>
     {
       this.Set(fullKey, value);
     });
    }

    /// <summary>
    /// 设置指定完全键的值为null
    /// </summary>
    /// <param name="fullKey">完全键</param>
    /// <returns></returns>
    public ICacheManager Clear(string fullKey)
    {
      if (fullKey.IsNullOrEmpty())
      {
        throw new Exception("错误的键！" + fullKey);
      }
      string[] fullKeys = fullKey.Split(',');
      foreach (string key in fullKeys)
      {
        CacheKey keyObj = CacheKey.Create(key);
        if (keyObj.IsNullOrEmpty())
        {
          return this;
        }
        if (keyObj.ProxyKey.IsNotNullOrEmpty())
        {
          ICacheProxy proxy = this[keyObj.ProxyKey];
          if (proxy.IsNullOrEmpty())
          {
            return this;
          }
          if (keyObj.ObjectKey.IsNotNullOrEmpty())
          {
            IDictionary cacheObject = proxy.GetCacheObject(keyObj);
            if (cacheObject != null)
            {
              if (keyObj.ValueKey.IsNotNullOrEmpty())
              {
                cacheObject.Remove(keyObj.ValueKey);
              }
              else
              {
                cacheObject.Clear();
              }
            }
          }
          else
          {
            proxy.Clear();
          }
        }
      }

      return this;
    }

    /// <summary>
    /// 异步删除指定的缓存
    /// </summary>
    /// <param name="fullKey"></param>
    /// <returns></returns>
    public void ClearAsync(string fullKey)
    {
      Task.Run(() =>
     {
       this.Clear(fullKey);
     });
    }

    /// <summary>
    /// 获取缓存代理的枚举对象
    /// </summary>
    public IEnumerable<ICacheProxy> CacheProxys
    {
      get
      {
        return this._htCacheProxy.Values.Cast<ICacheProxy>();
      }
    }

    /// <summary>
    /// 获取缓存代理的枚举对象名称
    /// </summary>
    public ICollection CacheProxyKeys
    {
      get
      {
        return this._htCacheProxy.Keys;
      }
    }

    /// <summary>
    /// 清除所有缓存代理中的缓存数据
    /// </summary>
    public ICacheManager ClearAllCacheProxy()
    {
      foreach (ICacheProxy proxy in this.CacheProxys)
      {
        if (proxy != null)
        {
          proxy.Clear();
        }
      }
      return this;
    }

    /// <summary>
    /// 获取默认的缓存代理对象
    /// </summary>
    public ICacheProxy DefaultCacheProxy
    {
      get
      {
        return this[DEFAULT_CACHE_PROXY_KEY];
      }
    }

    /// <summary>
    /// 注册缓存实例类型
    /// </summary>
    /// <param name="name"></param>
    /// <param name="typeFullName"></param>
    public virtual void RegisterCacheType(string name, string typeFullName)
    {
      _cacheTypesCache.Add(name, typeFullName);
    }

    /// <summary>
    /// 注册缓存代理对象
    /// </summary>
    /// <param name="name">代理名称</param>
    /// <param name="typeName">代理的类型名称</param>
    /// <param name="enable">是否开启</param>
    /// <param name="customerProperties">自定义属性集合</param>
    /// <returns></returns>
    public virtual ICacheProxy RegisterCacheProxy(string name, string typeName, IDictionary customerProperties = null, bool enable = true)
    {
      var typeFullName = string.Empty;
      if (typeName.IsNotNullOrEmpty())
      {
        _cacheTypesCache.TryGetValue(typeName, out typeFullName);
      }
      Type type = Type.GetType(typeFullName);
      if (type == null)
      {
        throw new NullReferenceException($"指定的类型：{typeFullName}无效！");
      }
      return this.RegisterCacheProxy(name, type, customerProperties, enable);
    }

    public virtual ICacheProxy RegisterCacheProxy<T>(string name, IDictionary customerProperties = null, bool enable = true)
    {
      var type = typeof(T);
      return this.RegisterCacheProxy(name, type, customerProperties, enable);
    }

    public virtual ICacheProxy RegisterCacheProxy(string name, Type cacheProxyType, IDictionary customerProperties = null, bool enable = true)
    {
      var cacheProxy = cacheProxyType.Assembly.CreateInstance(cacheProxyType.FullName) as ICacheProxy;
      if (cacheProxy == null)
      {
        throw new NullReferenceException($"指定的类型：{cacheProxyType.FullName}无效！");
      }
      cacheProxy.Name = name;
      cacheProxy.Enable = enable;
      cacheProxy.Initialize(customerProperties);
      _htCacheProxy[name] = cacheProxy;
      cacheProxy.OnErrorEvent += CacheProxy_OnError;
      return cacheProxy;
    }

    private void CacheProxy_OnError(IDictionary exc)
    {
      if (OnErrorEvent != null)
      {
        OnErrorEvent(exc);
      }
    }

    public T Get<T>(CacheKey keyObj, T defaultValue = default(T))
    {
      return (T)this.Get<T>(keyObj.ToString(), defaultValue);
    }

    public T Get<T>(CacheKey keyObj, Func<T> funDefaultValue)
    {
      return (T)this.Get<T>(keyObj.ToString(), funDefaultValue);
    }
  }
}
